package com.sh.d1.gatewayserver;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.log4j.PropertyConfigurator;
import com.sh.util.NacosConfigUtil;
import com.sh.util.RedisUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 网关服务器入口
 */
public class GatewayServer {
    /**
     * 日志对象
     */
    static private final Logger LOGGER = LoggerFactory.getLogger(GatewayServer.class);


    /**
     * 服务器id
     */
    static private String _Id = null;


    /**
     * 获取服务器Id
     *
     * @return
     */
    static public String getId() {
        return _Id;
    }

    /**
     * 主函数
     *
     * @param argvArray 命令行参数
     */
    static public void main(String[] argvArray) {
        // 设置 log4j 属性文件
        PropertyConfigurator.configure(GatewayServer.class.getClassLoader().getResourceAsStream("log4j.properties"));

        CommandLine cmdLn = createCmdLn(argvArray);
        if (null == cmdLn) {
            System.exit(-1);
            return;
        }

        _Id = cmdLn.getOptionValue("server_id");
        NacosConfigUtil.init(cmdLn.getOptionValue("nacos_server_addr"),
                "DEFAULT_GROUP", "application.properties",5000);
        boolean success = NacosConfigUtil.loadAllConfigFromNacos();
        if (!success) {
            System.exit(-1);
            return;
        }

        RedisUtil.init();
        //解决两个网关登录问题
        RedisSusbcriberbak.startSubcriber();

        updateServerIdExpireTime();

        //发现游戏服务器
        GameServerFinder.startFindGameServer(cmdLn.getOptionValue("nacos_server_addr"));


        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup);
            b.channel(NioServerSocketChannel.class); // 非阻塞的信道, 拉客不停歇!
            b.childHandler(new ChannelInitializer<SocketChannel>() { // 告诉干活的这活应该怎么干?
                @Override
                public void initChannel(SocketChannel ch) {
                    // 在这里告诉干活的这活应该怎么干?
                    ch.pipeline().addLast(
                            new HttpServerCodec(), // 添加 Http 编解码器
                            new HttpObjectAggregator(65535), // 内容不能太长
                            new WebSocketServerProtocolHandler("/websocket"), // WebSocket 协议
                            new ClientMsgHandler()
                    );
                }
            });
            b.option(ChannelOption.SO_BACKLOG, 128);
            b.childOption(ChannelOption.SO_KEEPALIVE, true);

            // 绑定服务器端口号
            ChannelFuture f = b.bind(cmdLn.getOptionValue("bind_host"),
                    Integer.parseInt(cmdLn.getOptionValue("bind_port"))).sync();

            if (f.isSuccess()) {
                LOGGER.info(">>> 网关服务器启动成功! <<<");
            }

            f.channel().closeFuture().sync();
        } catch (Exception ex) {
            // 记录错误日志
            LOGGER.error(ex.getMessage(), ex);
        } finally {
            // 关闭服务器, 大家都歇了吧
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    static private CommandLine createCmdLn(String[] argvArry) {
        Options op = new Options();
        op.addRequiredOption(null, "server_id", true, "服务器id");
        op.addRequiredOption(null, "bind_host", true, "绑定主机地址");
        op.addRequiredOption(null, "bind_port", true, "绑定主机端口");
        op.addRequiredOption(null, "nacos_server_addr", true, "绑定注册中心地址");

        try {
            DefaultParser dp = new DefaultParser();
            return dp.parse(op, argvArry);
        } catch (ParseException ex) {
            LOGGER.error(ex.getMessage(), ex);
        }
        return null;
    }

    /**
     * 续约
     */
    static private void updateServerIdExpireTime() {
        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(() -> {
            try (Jedis redis = RedisUtil.getRedis()) {
               redis.pexpire("GatewayServer_"+getId(),8000);

            } catch (Exception ex) {
                LOGGER.error(ex.getMessage(), ex);
            }
        }, 0, 5, TimeUnit.SECONDS);
    }

}
